#include "../include/defs.h"
#include "../include/kc.h"
#include "../include/sleep.h"

#define CUANTUM_MAX 6

extern process_t procesos[];
extern int pidActual;
extern peticion peticionesDormir[];
extern int maxmem;

extern unsigned long *page_table;
extern unsigned long *page_directory;

void SaveESP(int ESP) {

	process_t *temporal;
	temporal = GetProcessByPid(pidActual);
	temporal->ESP = ESP;
	return;
}
int

bajarPaginasAnterior(int pid) {
	process_t *myProcess;
	if (pid == 0)
		return 0;
	myProcess = GetProcessByPid(pid);
	bajarPaginas(myProcess);
	return 0;
}

int levantaPaginasNuevo(int pid) {
	process_t *myProcess;
	if (pid == 0)
		return 0;
	myProcess = GetProcessByPid(pid);
	levantaPaginas(myProcess);
	return 0;
}

int bajarPaginas(process_t * myProcess) {
	int pag_o, pag_i, j, i;

	if (myProcess == NULL) {

		pag_o = INITIAL_PAGE;
		pag_i = maxmem / 4; // Da la ultima pagina a levantar*/
		return 0;

	} else {
		pag_o = (int) myProcess -> stackstart / 4096;
		pag_i = (int) (myProcess->heapstart + myProcess->heapsize) / 4096;
	}

	/* La posicion de la pagina dividido 1024 nos da la posicion en la tabla
	 de directorio de la tabla de paginas a la cual pertenece esa pagina */
	for (i = pag_o / 1024; i <= pag_i / 1024; i++) {

		int upTo;

		page_table = page_directory + 4096 * (i + 1);

		if (i != pag_o / 1024)
			j = 0;
		else
			j = pag_o % 1024;

		if (i == pag_i / 1024)
			upTo = (pag_i - pag_o) % 1024 + pag_o % 1024;
		else
			upTo = 1024;

		for (; j < upTo; j++)
			page_table[j] = page_table[j] & 0xFFFFFFFE;

		page_directory[i] = (unsigned long) page_table;
		page_directory[i] = page_directory[i] & 0xFFFFFFFE;
		;

	}

	return 0;

}

int levantaPaginas(process_t * myProcess) {

	int pag_o, pag_i, j, i;

	if (myProcess == NULL) {
		pag_o = INITIAL_PAGE;
		pag_i = maxmem / 4; // Da la ultima pagina a levantar*/
	} else {
		pag_o = (int) myProcess -> stackstart / 4096;
		pag_i = (int) (myProcess->heapstart + myProcess->heapsize) / 4096;

	}

	/* La posicion de la pagina dividido 1024 nos da la posicion en la tabla
	 de directorio de la tabla de paginas a la cual pertenece esa pagina */
	for (i = pag_o / 1024; i <= pag_i / 1024; i++) {
		int upTo;

		page_table = page_directory + 4096 * (i + 1);

		if (i != pag_o / 1024)
			j = 0;
		else
			j = pag_o % 1024;

		if (i == pag_i / 1024)
			upTo = (pag_i - pag_o) % 1024 + pag_o % 1024;
		else
			upTo = 1024;

		for (; j < upTo; j++)
			/*page_table[j] = page_table[j] | 7;*/
			page_table[j] = page_table[j] | 0x1;

		page_directory[i] = (unsigned long) page_table;
		page_directory[i] = page_directory[i] | 0x1;

	}

	return 0;
}


void initScheduler(void) {
	int i, j;

	void *stack = (void*)0x300000;

	/* todos los slots estan libres */
	for (i = 0; i < MAXPROCESOS; i++)
		procesos[i].free_slot = 1;

	/* no hay procesos en la lista de sleep */
	for (i = 0; i < MAXPROCESOS; i++)
		peticionesDormir[i].time = 0;
}

/*
 * 	Get Next Process
 * 				recibo el stack pointr del actual
 * 			y y recibo la proxima tarea.
 * 				bajo las paginas del proceso actual;
 * 				el nuevo proceso es el que recibí t retorno el nuevo stack
 * 				y lavanto paginas del nuevo proc.
 *
 */

int GetNextProcess(int esp) {
	process_t *temporal;
	SaveESP(esp);
	/*
	 * De acuerdo al algoritmo de scheluding
	 * me va a dar el siguiente proceso a ejectuar
	 */
	temporal = GetNextTask();

	bajarPaginasAnterior(pidActual);

	pidActual = temporal->pid;

	levantaPaginasNuevo(pidActual);
	return temporal->ESP;
}

